package com.shutuo.callnummeiwei.net;

import android.util.SparseArray;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;



import org.json.JSONException;
import org.json.JSONObject;

import ashy.earl.common.data.JsonParser;
import ashy.earl.common.util.L;

/**
 * 用于{@link SocketWire}中的数据包序列化，反序列化。其序列化，反序列化发生在子线程，而非调用者线程，因此可以减少在UI
 * 线程使用的时候出现的卡顿。
 */
public class PacketConvert {
    private static final String TAG = "PacketConvert";
    private final SparseArray<PacketParser> mPacketParsers = new SparseArray<>();
    private final String mTag;

    public PacketConvert(String mTag) {
        this.mTag = mTag;
    }

    public <T> void registMsgParser(int type, JsonParser<T> parser) {
        registMsgParser(type, new JsonParserImpl<>(parser));
    }

    public void registMsgParser(int type, PacketParser<?> parser) {
        PacketParser jsonParser = mPacketParsers.get(type);
        if (jsonParser != null) {
            throw new IllegalAccessError("type[" + type + "] already registed:" + jsonParser);
        }
        mPacketParsers.put(type, parser);
    }

    @SuppressWarnings("unchecked")
    public void convertPacket(SocketWire.Packet packet) {
        if (packet == null || (packet.data == null && packet.parsedData == null) ||
            (packet.data != null && packet.parsedData != null)) {
            return;
        }
        if (packet.data == null) {
            PacketParser parser = mPacketParsers.get(packet.arg0);
            if (parser == null) {
                throw new IllegalStateException("Unsupport message type:" + packet.arg0);
            }
            byte[] data = parser.toData(packet.parsedData);
            if (data == null) {
                throw new NullPointerException("parser[" + parser + "] give null result!");
            }
            packet.data = data;
            packet.dataStart = 0;
            packet.dataLength = packet.data.length;
            return;
        }
        //if (packet.parsedData == null)
        PacketParser parser = mPacketParsers.get(packet.arg0);
        if (parser == null) {
            L.e(mTag, "%s~ Unsupport packet, type:%d", TAG, packet.arg0);
            return;
        }
        try {
            packet.parsedData = parser.toObj(packet.data, packet.dataStart, packet.dataLength);
        } catch (Throwable e) {
            L.e(mTag, e, "%s~ convertPacket failed, type:%d, data:%s", TAG, packet.arg0,
                new String(packet.data, packet.dataStart, packet.dataLength));
        }
    }

    public static class JsonParserImpl<T> implements PacketParser<T> {
        private final JsonParser<T> mJsonImpl;

        public JsonParserImpl(JsonParser<T> jsonImpl) {
            mJsonImpl = jsonImpl;
        }

        @Nullable
        @Override
        public byte[] toData(@NonNull T obj) {
            JSONObject json = mJsonImpl.toJson(obj);
            if (json == null) return null;
            return json.toString().getBytes();
        }

        @Nullable
        @Override
        public T toObj(@NonNull byte[] data, int offset, int length) {
            String str = new String(data, offset, length);
            try {
                return mJsonImpl.onParse(new JSONObject(str));
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
}